package pf;

import java.io.FileDescriptor;
import basic.*;

public class HashTable {
	private int numBuckets;
	private HashEntry[] hashTable;
	
	
	/* if the file descriptor , how to parse them to integer */
	
	private final int Hash(FileDescriptor fd, PageNum pageNum) {
		return ((Integer.parseInt(fd.toString()) + pageNum.getPageNum()) % numBuckets);
	}
	
	public HashTable (int numBuckets) {
		this.numBuckets= numBuckets;
		hashTable= new HashEntry[numBuckets];
		for (int i= 0; i < numBuckets; i++) 
			hashTable[i]= null;
	}
	
	
	public ReturnCode find (FileDescriptor fd, PageNum pageNum, Slot slot) {
		int bucket= Hash(fd, pageNum);
		
		if (bucket < 0) {
			return ReturnCode.PF_HASHNOTFOUND;
		}
		
		for (HashEntry entry= hashTable[bucket]; 
			entry != null; 
			entry= entry.next) {
			if (entry.fd == fd && entry.pageNum == pageNum) {
				slot.setSlotValue(entry.slot);
				return ReturnCode.PF_SUCCESS;
			}
		}
		return ReturnCode.PF_HASHNOTFOUND;		
	}
	
	public ReturnCode insert (FileDescriptor fd, PageNum pageNum, Slot slot) {
		int bucket= Hash(fd, pageNum);
		
		HashEntry entry;
		for (entry= hashTable[bucket]; 
			entry != null; 
			entry= entry.next) {
			if (entry.fd == fd && entry.pageNum == pageNum) {
				return ReturnCode.PF_HASHPAGEEXIST;
			}
		}
		
		if ((entry= new HashEntry()) == null)
			return ReturnCode.PF_NOMEM;
		
		entry.fd= fd;
		entry.pageNum= pageNum;
		entry.slot= slot.getSlotValue();
		entry.next= hashTable[bucket];
		entry.previous= null;
		if (hashTable[bucket] != null)
			hashTable[bucket].previous= entry;
		hashTable[bucket]= entry;
		
		return ReturnCode.PF_SUCCESS;
	}
	

	public ReturnCode delete (FileDescriptor fd, PageNum pageNum) {
		int bucket= Hash(fd, pageNum);
		
		HashEntry entry;
		for (entry= hashTable[bucket]; 
			entry != null; 
			entry= entry.next) {
			if (entry.fd == fd && entry.pageNum == pageNum)
				break;
		}
		
		if (entry == null) 
			return ReturnCode.PF_HASHNOTFOUND;
		
		if (entry == hashTable[bucket])
			hashTable[bucket]= entry.next;

		if (entry.previous != null)
			entry.previous.next= entry.next;
		
		if (entry.next != null)
			entry.next.previous= entry.previous;
		
		return ReturnCode.PF_SUCCESS;
	}
}
